#include "ScriptFunction.h"

#include "GSharpClass.h"
#include "Reflection/FunctionList.h"

#include "ScriptRuntime/Interpreter/FunctionInterpreter.h"

#include "ScriptRuntime/ScriptSubsystem.h"

// CAny CWrapFunctionBody::Invoke(RObject *InObject, const TVector<CAny> &InArgs)
// {
//     return Function->Invoke(InObject, InArgs);
// }

CScriptFunction::CScriptFunction(
    CFunctionList* InParentList
    , const CString &InFunctionName
    , const SDecoratedType& InReturnType
    ,const TVector<SDecoratedType>& InParameters
    ,const TVector<CString> & InParameterNames
    ,TMap<EFunctionFlags, SReflectionMetaDataValue> InMetaData
    )
:CFunction(
    InParentList
    ,InFunctionName
    ,InReturnType
    ,InParameters
    ,InMetaData
    )
{
    ReturnType=InReturnType;

    ParameterNames = InParameterNames;
}

CAny CScriptFunctionBody::Invoke(const TVector<CAny> &InArgs)
{
    assert(RScriptSubsystem::Get() && "Script Subsystem is not initialized");

    std::shared_ptr<CFunctionInterpreter> Interpreter=std::make_shared<CFunctionInterpreter>(Owner->BreakpointSlots,Owner);

    RScriptSubsystem::Get() -> ScriptCallStack.Add(Interpreter);

    Interpreter->ArgumentStack.Reserve(InArgs.Num());

    uint32_t ArgIndex=0;
    if(!Owner->IsStatic())
    {
        // non static function
        // push this pointer
        Interpreter->ArgumentStack.Emplace(InArgs[0]);
        ArgIndex++;
    }

    for(;ArgIndex<InArgs.Num();ArgIndex++)
    {
        Interpreter->ArgumentStack.Emplace(InArgs[ArgIndex]);
    }

    Interpreter->ScriptFile=Owner->File;
    Interpreter->ByteCodeStart=Owner->StartIndex;
    Interpreter->FunctionLines=Owner->LinePositions;

    Interpreter->VariableStack.Reserve(Owner->Variables.Num());
    for(auto Variable :Owner->Variables)
    {
        Interpreter->VariableStack.Emplace(Variable.Type,Variable.Type->CreateInstance());
    }


    CAny Result=Interpreter->RunScript();

    RScriptSubsystem::Get() -> ScriptCallStack.RemoveLast();

    return Result;
}
